#! /usr/bin/env python
#coding=utf-8

import pygame
import os
import glob
import random

HORIZ_LEFT = 1
HORIZ_RIGHT = 2
HORIZ_CENTER = 4
VERT_TOP = 8
VERT_BOTTOM = 16
VERT_CENTER = 32

def extractFlags(x, y, w, h, align):
    
    if align & HORIZ_LEFT:
        x = x
    elif align & HORIZ_RIGHT:
        x = x - w
    elif align & HORIZ_CENTER:
        x = x - w / 2
    
    if align & VERT_TOP:
        y = y
    elif align & VERT_BOTTOM:
        y = y - h
    elif align & VERT_CENTER:
        y = y - h / 2
    
    return x, y

def drawAligned(surf, img, x, y, align = (HORIZ_LEFT | VERT_TOP)):        
    x, y = extractFlags(x, y, img.get_width(), img.get_height(), align)            
    surf.blit(img, (x, y))
    
def drawTextAligned(surf, fnt, string, x, y, color, align = (HORIZ_LEFT | VERT_TOP)):
    w, h = fnt.size(string)
    x, y = extractFlags(x, y, w, h, align)
    rendered = fnt.render(string, 1, color)
    surf.blit(rendered, (x, y))

def getShutterEffectDrawer(surf, img, scr_width, max_t):
    count = scr_width / img.get_rect().width        
    timestep = max_t / count
    max_t += timestep
    total_time = [timestep]
    def f(deltaMS):            
        x, t = 0, timestep
        if total_time[0] >= max_t:
            total_time[0] = max_t
        for idx in range(count):
            r, m = total_time[0] / t, 0            
            if r > 0:
                if total_time[0] - t >= timestep:
                    m = timestep - 2
                else:
                    m = total_time[0] - t
            alpha = (150 * m) / (timestep - 2)
            img.set_alpha(alpha)
            drawAligned(surf, img, x, 0, HORIZ_LEFT | VERT_TOP)
            x += img.get_rect().width            
            t += timestep
        total_time[0] += deltaMS
        return total_time[0] >= max_t
    return f

def getFallEffectDrawer(surf, scrWidth, scrHeight):
    numHoriz, numVert = 20, 10
    partWidth, partHeight = scrWidth / numHoriz, scrHeight / numVert    
    effectFinished = [False]
    parts = []
    # create surfaces and fill them with the screen image
    for idx in range(numHoriz * numVert):
        # ok so, this looks horrible but it's actually very simple
        # we create a list of sublists where each sublist consists of
        # [x, y, x0, y0, random number in interval [0.05, 0.01) which will represent speed, surface of size partWidth, partHeight]
        parts.append([0, 0, 0, 0, random.uniform(0.05, 0.1), pygame.Surface((partWidth, partHeight))])
    
    # here what we do is taking each of the small early generated surface and
    # render the whole screen into them with specific offset to the top-left,
    # so each surface contains a part of the whole screen
    x, y = 0, 0    
    for part in parts:        
        part[5].blit(surf, (x, y))
        part[0], part[1], part[2], part[3] = abs(x), abs(y), abs(x), abs(y)
        x -= partWidth
        if abs(x) == scrWidth:
            x = 0
            y -= partHeight

    def f(deltaMS):
        # draw generated parts
        if not effectFinished[0]:
            flag = True
            # here we just move generated parts according to the parabolic equation
            # with its extremum point at x0, y0, so the equation will be as follows
            # y = y0 + (0.2 * (x - x0) ^ 2) or in our terms
            # part[1] = part[3] + (0.2 * (part[0] - part[2]) ** 2)
            #
            # it's easy :]
            for part in parts:
                surf.blit(part[5], (part[0], part[1]))
                part[0] += part[4] * deltaMS
                part[1] = part[3] + (0.2 * (part[0] - part[2]) ** 2)
                if part[1] < scrHeight:
                    flag = False
            if flag:
                effectFinished[0] = True
    return f

def getFilesByMask(watch_dir, mask):
    pattern = os.path.join(watch_dir, mask) 
    output = []
    for f in glob.glob(pattern): 
        if not os.path.isfile(f): #already did the join in the pattern 
            continue
        output.append(f)
    return output
    
def AABBAABB_Intersect(aabb1, aabb2):
    # checks whether 2 aabbs intersect
    ox1 = aabb1.coord_x + aabb1.half_width
    ox2 = aabb2.coord_x + aabb2.half_width
    if abs(ox2 - ox1) > aabb1.half_width + aabb2.half_width: return False
    oy1 = aabb1.coord_y + aabb1.half_height
    oy2 = aabb2.coord_y + aabb2.half_height
    if abs(oy2 - oy1) > aabb1.half_height + aabb2.half_height: return False
    return True

def getCirclesReflection(c1, v1, c2, v2):
    """
        c1 - first circle center, v1 - first circle speed vector
        c2 - second circle center, v2 - second circle speed vector
        
        computes reflection of two circles and returns their
        result speeds
    """
    # compute normal
    n = normalize( ( c2[0] - c1[0], c2[1] - c1[1] ) )
    v12 = getReflection(v1, n)
    v22 = getReflection(v2, n)
    return v12, v22

def circlesCollide(c1, c2, r1, r2):
    dx, dy = c2[0] - c1[0], c2[1] - c1[1]
    return dx * dx + dy * dy <= (r1 + r2) ** 2

def normalize(v):
    # 2d-vector normalization
    inv_mag = 1.0 / (v[0] ** 2 + v[1] ** 2) ** 0.5
    return ( v[0] * inv_mag, v[1] * inv_mag )

def dot(a, b):
    # computes dot product of two 2d vectors
    return a[0] * b[0] + a[1] * b[1]

def sub(a, b):
    # substract vector b from vector a
    return ( (a[0] - b[0], a[1] - b[1]) )

def mul(a, n):
    # multiply vector a by number n
    return ( (a[0] * n, a[1] * n) )

def getReflection(v, n):
    """
        computes reflection of vector v assuming the n is
        a normal vector
        the formula is v1 = v - 2 * dot(n, v) * n
    """
    return sub(v, mul(mul(n, dot(n, v)), 2))

def linearInterp(start, end, t, t_max):
    return start + ((end - start) * t) / (1.0 * t_max)
